package com.example.springboottest.example.zookeeper.listener;

import com.example.springboottest.example.zookeeper.ZKclient;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.*;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;

import java.io.UnsupportedEncodingException;

/**
 * Curator 引入的 Cache 缓存机制的实现拥有一个系列的类型，包括了 Node Cache、Path Cache 和 Tree Cache 三组类。其中：
 * （1）Node Cache 节点缓存可用于 ZNode 节点的监听；
 * （2）Path Cache 子节点缓存可用于 ZNode 的子节点的监听；
 * （3）Tree Cache 树缓存是 Path Cache 的增强，不光能监听子节点，还能监听 ZNode 节点自身。
 */
public class ZkCuratorWatcherDemo {
    private String workerPath = "/test/listener/remoteNode";
    private String subWorkerPath = "/test/listener/remoteNode/id-";

    public static void main(String[] args) {
        new ZkCuratorWatcherDemo().testNodeCache();
    }

    public void testNodeCache() {
        //检查节点是否存在，没有则创建
        boolean isExist = ZKclient.instance.isNodeExist(workerPath);
        if (!isExist) {
            ZKclient.instance.createNode(workerPath, null);
        }
        CuratorFramework client = ZKclient.instance.getClient();
        try {
            NodeCache nodeCache =
                    new NodeCache(client, workerPath, false);
            //当前node
            NodeCacheListener listener = new NodeCacheListener() {
                @Override
                public void nodeChanged() throws Exception {
                    ChildData childData = nodeCache.getCurrentData();
                    System.out.println("ZNode 节点状态改变, path=" + childData.getPath());
                    System.out.println("ZNode 节点状态改变, data=" + new
                            String(childData.getData(), "Utf-8"));
                    System.out.println("ZNode 节点状态改变, stat=" + childData.getStat());
                }
            };


            /**
             * PathChildrenCache 子节点缓存用于子节点的监听，监控当前节点的子节点被创建、更新或者删除，需要强调：
             * ⚫ 只能监听子节点，监听不到当前节点。
             * ⚫ 不能递归监听，子节点下的子节点不能递归监控。
             */
            PathChildrenCache childrenCache =
                    new PathChildrenCache(client, workerPath, true);
            PathChildrenCacheListener childListener = new PathChildrenCacheListener() {
                @Override
                public void childEvent(CuratorFramework client, PathChildrenCacheEvent
                        event) {
                    try {
                        ChildData data = event.getData();
                        switch (event.getType()) {
                            case CHILD_ADDED:
                                System.out.println("子节点增加, path=" + data.getPath() + ", data=" +
                                        new String(data.getData(), "UTF-8"));
                                break;
                            case CHILD_UPDATED:
                                System.out.println("子节点更新, path=" + data.getPath() + ", data=" + new String(data.getData(), "UTF-8")
                                );
                                break;
                            case CHILD_REMOVED:
                                System.out.println("子节点删除, path=" + data.getPath() + ", data=" +
                                        new String(data.getData(), "UTF-8"));
                                break;
                            default:
                                break;
                        }
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                }
            };


            //启动节点的事件监听
            nodeCache.getListenable().addListener(listener);
            nodeCache.start();

            childrenCache.getListenable().addListener(childListener);
            childrenCache.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE);
            // 第 1 次变更节点数据
//            client.setData().forPath(workerPath, "第 1 次更改内容".getBytes());
//            Thread.sleep(1000);
//            // 第 2 次变更节点数据
//            client.setData().forPath(workerPath, "第 2 次更改内容".getBytes());
//            Thread.sleep(1000);
//            // 第 3 次变更节点数据
//            client.setData().forPath(workerPath, "第 3 次更改内容".getBytes());
//            Thread.sleep(1000);
//            // 第 4 次变更节点数据
//            client.delete().forPath(workerPath);
            Thread.sleep(Integer.MAX_VALUE);
        } catch (Exception e) {
            System.out.println("创建 NodeCache 监听失败, path=" + workerPath);
        }
    }
}
